# -*- coding: utf-8 -*- 
"""
Created by lpf on 2016/11/30 11:17:01.
@author: 李鹏飞
"""
from __future__ import absolute_import
from __future__ import unicode_literals

import datetime
import logging

from auction.apps.common.models import ApschedulerLog
from auction.apps.common.start_scheduler import scheduler
from auction.apps.fund.service_refund import refund_bid
from auction.apps.house.models import House
from auction.apps.house.service_house import house_end_time
from auction.apps.special.models import Special
from auction.apps.trade.models import BidLog
from auction.settings import conf

logger = logging.getLogger(__name__)

""" 重启时查询apscheduler_log表,
已执行的跳过,
没执行的没过期的加回定时器,
已过期的马上执行,
执行完改is_finish=true;
"""


# 提醒用户:短信,微信
# 拍卖的结束,
# 延时周期,延一次改一次时间
# 保留价,
# 专场的结束
# 补足认购金提醒


def run_timer():
    """定时器执行的方法
    重启时查询apscheduler_log表,判断是否执行，过期没执行的立即
    """
    now = datetime.datetime.now()
    # 查询已过期的,没执行的
    log_list = ApschedulerLog.objects.filter(run_time__lte=now, is_finish=False)
    logger.debug("apscheduler_log表未执行的数据[%s]" % log_list)
    for log in log_list:
        # 执行方法
        eval(log.function)(log.id)
        # 更新为已执行
        log.update_finish()
    logger.debug("apscheduler_log表执行完毕")


def special_house_timer(special):
    """查询专场下的房源,加定时器"""
    house_list = special.house.all()
    for house in house_list:
        house.is_shelf = 1
        house.shelf_time = datetime.datetime.now()
        house.audit_status = 2
        house.save()
        house_timer(house)


def special_timer(special):
    """专场定时器,开始,结束
    专场下的房源也加定时器
    """
    add_job('special_start', special.id, special.start_time)
    add_job('special_end', special.id, special.end_time)
    special_house_timer(special)


def special_start(log_id):
    """专场开始时间到,处理"""
    try:
        log = get_log(log_id)
        # 查询审核通过的
        special = Special.objects.get(pk=log.args, audit_status=2)
    except Exception as e:
        logger.error("special_start查询专场[%s]出错[%s]" % (log.args, e))
    else:
        # 已经开始的
        if special.start_time <= log.run_time:
            logger.debug("专场竞拍时间已经开始")
            special.update_status(0)
        else:
            # 未开始
            logger.debug("专场[%s]开始时间[%s]未到" % (special.id, special.start_time))
            # 重新加定时器
            log.update_run_time(special.start_time)
            sched_job = scheduler.add_job(special_start, 'date', run_date=log.run_time, args=[log.id], id=log.job_id,
                                          replace_existing=True)
            logger.debug("专场[%s]重新加定时器[%s]" % (special.id, sched_job))


def special_end(log_id):
    """专场结束时间到,处理"""
    try:
        log = get_log(log_id)
        # 查询审核通过的
        special = Special.objects.get(pk=log.args, audit_status=2)
    except Exception as e:
        logger.error("special_end查询专场[%s]出错[%s]" % (log.args, e))
    else:
        # 已经结束的
        if special.end_time <= log.run_time:
            logger.debug("专场竞拍时间已经结束")
            special.update_status(2)
        else:
            # 未开始
            logger.debug("专场[%s]结束时间[%s]未到" % (special.id, special.end_time))
            # 重新加定时器
            log.update_run_time(special.end_time)
            sched_job = scheduler.add_job(special_end, 'date', run_date=log.run_time, args=[log.id], id=log.job_id,
                                          replace_existing=True)
            logger.debug("专场[%s]重新加定时器[%s]" % (special.id, sched_job))


def house_timer(house):
    """房源结束倒计时定时器,开始竞拍是倒计时
    客服审核通过加这个定时器
    :param: house:房源对象
    """
    add_job('house_start', house.id, house.auctionway.start_time)
    add_job('house_end', house.id, house.auctionway.end_time)


def house_start(log_id):
    """房源开始竞拍时间到了处理"""
    try:
        log = get_log(log_id)
        # 查询审核通过的上架的房源
        house = House.shelf.get(pk=log.args, audit_status=2)
    except Exception as e:
        logger.error("house_start查询房源[%s]出错[%s]" % (log.args, e))
    else:
        # 已经开始的
        if house.auctionway.start_time <= log.run_time:
            logger.debug("房源竞拍时间已经开始")
            house.update_status(0)
        else:
            # 未开始
            logger.debug("房源[%s]开始时间[%s]未到" % (house.id, house.auctionway.start_time))
            # 重新加定时器
            log.update_run_time(house.auctionway.start_time)
            sched_job = scheduler.add_job(house_start, 'date', run_date=log.run_time, args=[log.id], id=log.job_id,
                                          replace_existing=True)
            logger.debug("房源[%s]重新加定时器[%s]" % (house.id, sched_job))


def house_end(log_id):
    """房源竞拍结束时间处理"""
    try:
        log = get_log(log_id)
        # 查询审核通过的上架的房源
        house = House.shelf.get(pk=log.args, audit_status=2)
    except Exception as e:
        logger.error("house_end查询房源[%s]出错[%s]" % (log.args, e))
    else:
        # 两种竞拍,判断该房源结束拍卖
        
        # 先判断房源状态
        if house.auction_status != 0:
            # 不是正在热拍的
            logger.debug("房源[%s]不是正在热拍的,不执行竞拍结束处理" % house.id)
            return
        # 先判断竞拍类型
        if house.auctionway.type == 0:  # 即时拍
            # 判断有没有即时周期的结束时间,有人出价则有
            if house.auctionway.instant_time:
                # 定时器执行时间小于即时结束时间,表示有另一个人竞拍,即时周期延后,则不处理,否则结束房源
                if log.run_time < house.auctionway.instant_time:
                    # 又有另一个人出价,即时周期延后，不执行操作
                    logger.debug("又有另一个人出价,即时周期延后，不执行操作")
                    return
                else:
                    # 没有另一个人竞拍,最高价者成交房源
                    logger.debug("没有另一个人竞拍,最高价者成交房源")
                    _update_house(house)
            else:
                # 没有即时结束时间,用房源结束时间判断
                logger.debug("没有即时结束时间,用房源结束时间判断")
                _update_end_time(house, log)
        else:  # 抢先拍
            logger.debug("该房源是抢先拍")
            _update_end_time(house, log)


def _update_end_time(house, log):
    """判断房源结束时间和定时器运行时间,没到的重新加定时器"""
    if house.auctionway.end_time <= log.run_time:
        logger.debug("房源竞拍时间已结束")
        # 确定房源结束时,判断出价信息,更新房源
        _update_house(house)
    else:
        logger.debug("房源[%s]结束时间[%s]未到" % (house.id, house.auctionway.end_time))
        # 重新加定时器
        log.update_run_time(house.auctionway.end_time)
        sched_job = scheduler.add_job(house_end, 'date', run_date=log.run_time, args=[log.id], id=log.job_id,
                                      replace_existing=True)
        logger.debug("房源[%s]重新加定时器[%s]" % (house.id, sched_job))


def _update_house(house):
    """确定房源结束时,判断出价信息,更新房源"""
    try:
        # 查询出价
        bid_log = BidLog.objects.get(house=house, is_legal=0, status=1)
    except BidLog.DoesNotExist:
        logger.debug("没人出价-流拍")
        # 没人出价-流拍;
        status = 3
    except Exception as e:
        logger.error(e)
        return
    else:
        # 有人出价-判断保留价;
        if house.auctionway.reserve_price and house.auctionway.reserve_price > bid_log.price:
            # 有保留价的 且保留价大于用户的出价,-加定时器1小时,
            logger.debug("有保留价的且未达到")
            status = 4
            # 加保留价定时器 todo 消息通知
            reserve_price_timer(house)
        else:
            # 没有保留价的-成交;
            logger.debug("没有保留价的-成交")
            status = 2
            # 创建订单表
            bid_log.create_order()
    house.update_status(status)
    # 除最高价,其余退款
    refund_bid(house)
    logger.debug("房源[%s]更新状态到[%s]" % (house.id, status))


def instant_period_timer(house):
    """加即时周期30分后结束房源的定时器"""
    # 已经判断过是否在结束时间内30分钟,直接加定时器
    add_job('house_end', house.id, house.auctionway.instant_time)


def reserve_price_timer(house):
    """保留价倒计时定时器"""
    run_time = house_end_time(house.auctionway) + datetime.timedelta(minutes=conf.reserve_time)
    add_job('reserve_price_end', house.id, run_time)


def reserve_price_end(log_id):
    """保留价倒计时结束处理
    """
    try:
        log = get_log(log_id)
        # 查询保留中的房源,没查到的是已加价购买,查到的是流拍
        house = House.shelf.get(pk=log.args, audit_status=4)
    except Exception as e:
        logger.error(e)
    else:
        # 流拍
        house.update_status(3)
        # 给最高价者退款
        refund_bid(house, is_all=True)


def deposit_timer():
    """认购金72小时内支付定时器"""
    pass


def add_job(func, args, run_time, trigger='date'):
    """通用,添加定时器,及记录表
    :param func:str 执行方法
    :param args:str 执行方法的参数 如house.id
    :param run_time:datetime 执行时间
    :param trigger:str 定时器类型 date,cron,interval
    """
    # 记录该定时器事件
    log = ApschedulerLog.objects.create(function=func, args=args,
                                        job_id='{}_{}'.format(func, args),
                                        run_time=run_time)
    # 加定时器，replace_existing:覆盖重复方法
    job = scheduler.add_job(eval(func), trigger, run_date=log.run_time, args=[log.id], id=log.job_id,
                            replace_existing=True)
    logger.debug("房源/专场[%s]加[%s]定时器成功[%s]" % (args, func, job))


def get_log(log_id):
    """查询定时器记录表,及更新为已执行
    :param log_id: ApschedulerLog表id
    """
    log = ApschedulerLog.objects.get(pk=log_id, is_finish=False)
    # 关定时器
    log.update_finish()
    return log
